/*-------------------------------------------------------------------------
 *
 * pqsignal.c
 *	  后端信号（2）支持（另见 src/port/pqsignal.c）
 *
 * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group
 * Portions Copyright (c) 1994, Regents of the University of California
 *
 *
 * IDENTIFICATION
 *	  src/backend/libpq/pqsignal.c
 *
 * ------------------------------------------------------------------------
 */

#include "postgres.h"

#include "libpq/pqsignal.h"


/* 全局变量 */
sigset_t	UnBlockSig,
			BlockSig,
			StartupBlockSig;


/*
 * 初始化 BlockSig、UnBlockSig 和 StartupBlockSig。
 *
 * BlockSig 是在我们尝试屏蔽信号时要屏蔽的信号集。这包括我们通常期望接收到的所有信号，但不包括应该永远不被关闭的信号。
 *
 * StartupBlockSig 是在启动数据包收集期间要屏蔽的信号集；本质上是 BlockSig 减去 SIGTERM、SIGQUIT、SIGALRM。
 *
 * UnBlockSig 是在我们不想屏蔽信号时要屏蔽的信号集。
 */
void pqinitmask(void)
{
	sigemptyset(&UnBlockSig);

	/* 注意：InitializeLatchSupport() 修改 UnBlockSig。 */

	/* 首先设置所有信号，然后清除一些。 */
	sigfillset(&BlockSig);
	sigfillset(&StartupBlockSig);

	/*
	 * 取消标记那些永远不应该被屏蔽的信号。这些信号名称并非在所有平台上都存在。大多数都存在，但为了保持一致性，可以在所有平台上进行条件编译...
	 */
#ifdef SIGTRAP
	sigdelset(&BlockSig, SIGTRAP);
	sigdelset(&StartupBlockSig, SIGTRAP);
#endif
#ifdef SIGABRT
	sigdelset(&BlockSig, SIGABRT);
	sigdelset(&StartupBlockSig, SIGABRT);
#endif
#ifdef SIGILL
	sigdelset(&BlockSig, SIGILL);
	sigdelset(&StartupBlockSig, SIGILL);
#endif
#ifdef SIGFPE
	sigdelset(&BlockSig, SIGFPE);
	sigdelset(&StartupBlockSig, SIGFPE);
#endif
#ifdef SIGSEGV
	sigdelset(&BlockSig, SIGSEGV);
	sigdelset(&StartupBlockSig, SIGSEGV);
#endif
#ifdef SIGBUS
	sigdelset(&BlockSig, SIGBUS);
	sigdelset(&StartupBlockSig, SIGBUS);
#endif
#ifdef SIGSYS
	sigdelset(&BlockSig, SIGSYS);
	sigdelset(&StartupBlockSig, SIGSYS);
#endif
#ifdef SIGCONT
	sigdelset(&BlockSig, SIGCONT);
	sigdelset(&StartupBlockSig, SIGCONT);
#endif

/* 启动时独有的信号 */
#ifdef SIGQUIT
	sigdelset(&StartupBlockSig, SIGQUIT);
#endif
#ifdef SIGTERM
	sigdelset(&StartupBlockSig, SIGTERM);
#endif
#ifdef SIGALRM
	sigdelset(&StartupBlockSig, SIGALRM);
#endif
}

/*
 * 为信号 "signo" 设置一个 postmaster 信号处理程序
 *
 * 返回上一个处理程序。
 *
 * 这仅在 postmaster 中使用，它对信号处理有其独特的方法。对于有处理程序的信号，我们在信号处理程序执行期间屏蔽所有信号。我们也不设置 SA_RESTART 标志；考虑到 postmaster 解锁信号的代码范围非常小，这应该是安全的。
 *
 * pqinitmask() 必须在之前被调用。
 *
 * 在 Windows 上，此函数只是 pqsignal() 的别名
 * （并注意它调用的是 src/backend/port/win32/signal.c 中的代码，
 * 而不是 src/port/pqsignal.c）。在该平台上，postmaster 的信号处理程序仍然必须自己屏蔽信号。
 */
pqsigfunc pqsignal_pm(int fc_signo, pqsigfunc fc_func)
{
#ifndef WIN32
	struct sigaction fc_act,
				fc_oact;

	fc_act.sa_handler = fc_func;
	if (fc_func == SIG_IGN || fc_func == SIG_DFL)
	{
		/* 在这些情况下，行为与 pqsignal() 相同 */
		sigemptyset(&fc_act.sa_mask);
		fc_act.sa_flags = SA_RESTART;
	}
	else
	{
		fc_act.sa_mask = BlockSig;
		fc_act.sa_flags = 0;
	}
#ifdef SA_NOCLDSTOP
	if (fc_signo == SIGCHLD)
		fc_act.sa_flags |= SA_NOCLDSTOP;
#endif
	if (sigaction(fc_signo, &fc_act, &fc_oact) < 0)
		return SIG_ERR;
	return fc_oact.sa_handler;
#else							/* WIN32 */
	return pqsignal(signo, func);
#endif
}
